/**
* @file: fs.js
* @brief: WebSocket版本文件系统远程调用功能实现，基于RPC封装
* @date: 2025-10-15
*
**************************/

/**
* 文件系统RPC接口封装类
* 用于提供远程文件系统操作的JavaScript接口
*/
class FsRpc {
    /**
    * 构造函数
    * @param {LuaRpc} luaRpc - Lua RPC实例
    */
    constructor(luaRpc) {
        this.luaRpc = luaRpc;
        this._initialized = false;
        // 创建初始化Promise但不等待其完成
        // 使用Promise的catch来避免未处理的Promise拒绝
        this._initializationPromise = this._initialize().catch(error => {
            console.error('FsRpc initialization failed:', error);
        });
        
        // 定义分包读写的块大小（10KB）
        this._CHUNK_SIZE = 10 * 1024;
    }

    /**
    * 异步初始化方法
    * 用于在类初始化时加载lib_fs和lib_buf模块
    * @private
    */
    async _initialize() {
        try {
            // 注册lib_fs库
            console.log('FsRpc: Registering lib_fs module...');
            await this.luaRpc.runCode(`
                if not fs then
                    fs = require("lib_fs")
                    print('lib_fs module registered')
                else
                    print('lib_fs module already registered')
                end

                if not buf then
                    buf = require("lib_buf")
                    print('lib_buf module registered')
                else
                    print('lib_buf module already registered')
                end
                if not zip then
                    zip = require("lib_zip")
                    print('lib_zip module registered')
                else
                    print('lib_zip module already registered')
                end
            `);
            
            console.log('FsRpc: All required modules (lib_fs and lib_buf) have been registered');
            this._initialized = true;
        } catch (error) {
            console.error('Failed to initialize FsRpc and load required modules:', error);
            this._initialized = false;
            throw error;
        }
    }

    /**
    * 确保FsRpc已初始化
    * 用于在调用文件系统方法前检查初始化状态
    * @private
    */
    async _ensureInitialized() {
        if (!this._initialized) {
            // 如果尚未初始化完成，则等待初始化
            if (!this._initializationPromise) {
                this._initializationPromise = this._initialize();
            }
            await this._initializationPromise;
        }
    }

    /**
    * 检查文件/目录是否存在
    * @param {string} path - 文件或目录路径
    * @returns {Promise<boolean>} - 返回文件/目录是否存在
    */
    async exist(path) {
        console.log(`FsRpc.exist() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 执行fs.exist函数
            const luaCode = `isExist = fs.exist("${path}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取isExist变量的值
            const result = await this.luaRpc.getGlobal('isExist');
            
            // 检查返回结果
            if (result && result.value !== undefined) {
                console.log(`获取isExist变量值: ${result.value}`);
                return result.value === true;
            }
            
            console.warn(`isExist变量未找到或值为undefined`);
            return false;
        } catch (error) {
            console.error(`检查路径存在性失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 创建目录
    * @param {string} path - 目录路径
    * @returns {Promise<number>} - 返回操作结果代码（0表示成功）
    */
    async mkdir(path) {
        console.log(`FsRpc.mkdir() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 执行fs.mkdir函数
            const luaCode = `ret = fs.mkdir("${path}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ret变量的值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`获取ret变量值: ${result.value}`);
                return result.value;
            }
            
            throw new Error('Failed to get return value');
        } catch (error) {
            console.error(`创建目录失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 删除目录
    * @param {string} path - 目录路径
    * @returns {Promise<number>} - 返回操作结果代码（0表示成功）
    */
    async rmdir(path) {
        console.log(`FsRpc.rmdir() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 执行fs.rmdir函数
            const luaCode = `ret = fs.rmdir("${path}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ret变量的值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`获取ret变量值: ${result.value}`);
                return result.value;
            }
            
            throw new Error('Failed to get return value');
        } catch (error) {
            console.error(`删除目录失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 打开文件
    * @param {string} path - 文件路径
    * @param {string} mode - 打开模式（"r"只读, "w"只写, "rw"读写等）
    * @returns {Promise<FileHandle>} - 返回文件句柄对象
    */
    async open(path, mode = "r") {
        console.log(`FsRpc.open() 被调用，路径: ${path}，模式: ${mode}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 生成一个唯一的标识符用于在Lua中引用这个文件句柄
            const handleId = 'fileHandle_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            
            // 直接打开文件并获取返回值
            await this.luaRpc.runCode(`${handleId} = fs.open("${path}", "${mode}")`);
            
            // 查询返回值
            const result = await this.luaRpc.getGlobal(handleId);
            
            // 检查返回值是否成功
            if (result && result.value !== undefined && result.value !== null) {
                const openResult = result.value;
                console.log(`文件 ${path} 打开成功，返回值:`, openResult);
                
                // 创建文件句柄对象并返回
                const fileHandle = new FileHandle(this.luaRpc, path, mode);
                fileHandle.handleId = handleId;
                fileHandle.openResult = openResult;
                fileHandle.isOpen = true;
                
                return fileHandle;
            } else {
                // 文件打开失败
                throw new Error(`文件 ${path} 打开失败，返回值为空`);
            }
        } catch (error) {
            console.error(`打开文件失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 重命名文件或目录
    * @param {string} oldPath - 原始路径
    * @param {string} newPath - 新路径
    * @returns {Promise<number>} - 返回操作结果代码（0表示成功）
    */
    async rename(oldPath, newPath) {
        console.log(`FsRpc.rename() 被调用，从: ${oldPath} 到: ${newPath}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 执行fs.rename函数
            const luaCode = `ret = fs.rename("${oldPath}", "${newPath}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ret变量的值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`获取ret变量值: ${result.value}`);
                return result.value;
            }
            
            throw new Error('Failed to get return value');
        } catch (error) {
            console.error(`重命名失败: ${oldPath} -> ${newPath}`, error);
            throw error;
        }
    }

    /**
    * 创建ZIP文件
    * @param {string} filename - ZIP文件路径
    * @returns {Promise<object>} - 返回ZIP对象
    */
    async zipCreate(filename) {
        console.log(`FsRpc.zipCreate() 被调用，路径: ${filename}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 生成一个唯一的标识符用于在Lua中引用这个ZIP对象
            const zipObjId = 'zipObj_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            
            // 执行zip.create函数
            const luaCode = `${zipObjId} = zip.create("${filename}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ZIP对象
            const result = await this.luaRpc.getGlobal(zipObjId);
            
            if (result && result.value !== undefined && result.value !== null) {
                console.log(`ZIP文件 ${filename} 创建成功`);
                // 返回ZIP对象引用（在JavaScript中作为一个标记对象）
                return { id: zipObjId };
            } else {
                throw new Error(`创建ZIP文件失败: ${filename}`);
            }
        } catch (error) {
            console.error(`创建ZIP文件失败: ${filename}`, error);
            throw error;
        }
    }

    /**
    * 加载已有的ZIP文件
    * @param {string} filename - ZIP文件路径
    * @returns {Promise<object>} - 返回ZIP对象
    */
    async zipLoad(filename) {
        console.log(`FsRpc.zipLoad() 被调用，路径: ${filename}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 生成一个唯一的标识符用于在Lua中引用这个ZIP对象
            const zipObjId = 'zipObj_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            
            // 执行zip.load函数
            const luaCode = `${zipObjId} = zip.load("${filename}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ZIP对象
            const result = await this.luaRpc.getGlobal(zipObjId);
            
            if (result && result.value !== undefined && result.value !== null) {
                console.log(`ZIP文件 ${filename} 加载成功`);
                // 返回ZIP对象引用（在JavaScript中作为一个标记对象）
                return { id: zipObjId };
            } else {
                throw new Error(`加载ZIP文件失败: ${filename}`);
            }
        } catch (error) {
            console.error(`加载ZIP文件失败: ${filename}`, error);
            throw error;
        }
    }

    /**
    * 关闭ZIP文件
    * @param {object} zipObj - ZIP对象
    * @returns {Promise<boolean>} - 返回操作是否成功
    */
    async zipClose(zipObj) {
        console.log(`FsRpc.zipClose() 被调用`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 执行ZIP对象的close方法（虽然底层是lua_zip_free，但Lua方法名仍然是close）
            const luaCode = `ret = ${zipObj.id}:close()`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回值
            const result = await this.luaRpc.getGlobal('ret');
            
            // 清理Lua中的ZIP对象引用
            await this.luaRpc.runCode(`${zipObj.id} = nil`);
            
            if (result && result.value !== undefined) {
                console.log(`ZIP文件关闭结果: ${result.value}`);
                return result.value === true;
            }
            
            return false;
        } catch (error) {
            console.error('关闭ZIP文件失败', error);
            throw error;
        }
    }

    /**
    * 添加项目到ZIP（可以是文件或目录）
    * @param {object} zipObj - ZIP对象
    * @param {string} archiveName - 在ZIP中的项目名
    * @param {string} srcPath - 源路径
    * @param {number} level - 压缩级别（默认为6）
    * @returns {Promise<boolean>} - 返回操作是否成功
    */
    async zipAddItem(zipObj, archiveName, srcPath, level = 6) {
        console.log(`FsRpc.zipAddItem() 被调用，ZIP内项目名: ${archiveName}，源路径: ${srcPath}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 规范化路径
            srcPath = srcPath.replace(/\\/g, '/');
            
            // 执行ZIP对象的addItem方法（自动检测文件或目录）
            const luaCode = `ret = ${zipObj.id}:addItem("${archiveName}", "${srcPath}", ${level})`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`添加项目到ZIP结果: ${result.value}`);
                if (!result.value) {
                    console.warn(`添加项目到ZIP失败: ${archiveName}，源路径: ${srcPath}`);
                }
                return result.value === true;
            }
            
            console.error(`添加项目到ZIP失败，无法获取返回值`);
            return false;
        } catch (error) {
            console.error(`添加项目到ZIP失败: ${archiveName}，源路径: ${srcPath}`, error);
            throw error;
        }
    }

    /**
    * 添加内存数据到ZIP
    * @param {object} zipObj - ZIP对象
    * @param {string} archiveName - 在ZIP中的文件名
    * @param {string|ArrayBuffer} data - 要添加的数据
    * @param {number} level - 压缩级别（默认为6）
    * @returns {Promise<boolean>} - 返回操作是否成功
    */
    async zipAddMem(zipObj, archiveName, data, level = 6) {
        console.log(`FsRpc.zipAddMem() 被调用，ZIP内文件名: ${archiveName}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 生成一个唯一的标识符用于在Lua中引用这个数据
            const dataId = 'zipData_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            
            // 将JavaScript数据转换为Lua字符串
            if (data instanceof ArrayBuffer) {
                // 对于ArrayBuffer，我们需要将其转换为base64并在Lua中解码
                const uint8Array = new Uint8Array(data);
                const base64Data = btoa(String.fromCharCode.apply(null, uint8Array));
                
                // 执行ZIP对象的addMem方法，使用base64数据
                const luaCode = `
                    local base64 = require("base64")
                    local binaryData = base64.decode("${base64Data}")
                    ret = ${zipObj.id}:addMem("${archiveName}", binaryData, ${level})
                `;
                console.log(`执行Lua代码添加二进制数据到ZIP`);
                await this.luaRpc.runCode(luaCode);
            } else {
                // 对于普通字符串，直接添加
                const luaCode = `ret = ${zipObj.id}:addMem("${archiveName}", [[${data}]], ${level})`;
                console.log(`执行Lua代码: ${luaCode}`);
                await this.luaRpc.runCode(luaCode);
            }
            
            // 获取返回值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`添加内存数据到ZIP结果: ${result.value}`);
                return result.value === true;
            }
            
            return false;
        } catch (error) {
            console.error(`添加内存数据到ZIP失败: ${archiveName}`, error);
            throw error;
        }
    }

    /**
    * 从ZIP中提取文件到目标文件
    * @param {object} zipObj - ZIP对象
    * @param {string} filename - ZIP中的文件名
    * @param {string} dstFilename - 目标文件路径
    * @returns {Promise<boolean>} - 返回操作是否成功
    */
    async zipExtractToFile(zipObj, filename, dstFilename) {
        console.log(`FsRpc.zipExtractToFile() 被调用，ZIP内文件名: ${filename}，目标文件路径: ${dstFilename}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 执行ZIP对象的extractToFile方法
            const luaCode = `ret = ${zipObj.id}:extractToFile("${filename}", "${dstFilename}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`从ZIP提取文件结果: ${result.value}`);
                return result.value === true;
            }
            
            return false;
        } catch (error) {
            console.error(`从ZIP提取文件失败: ${filename}`);
            throw error;
        }
    }

    /**
    * 从ZIP中提取所有文件到目标目录
    * @param {object} zipObj - ZIP对象
    * @param {string} dstDir - 目标目录路径
    * @returns {Promise<boolean>} - 返回操作是否成功
    */
    async zipExtractToDir(zipObj, dstDir) {
        console.log(`FsRpc.zipExtractToDir() 被调用，目标目录: ${dstDir}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 执行ZIP对象的extractToDir方法
            const luaCode = `ret = ${zipObj.id}:extractToDir("${dstDir}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`从ZIP提取所有文件到目录结果: ${result.value}`);
                return result.value === true;
            }
            
            return false;
        } catch (error) {
            console.error(`从ZIP提取所有文件到目录失败: ${dstDir}`);
            throw error;
        }
    }

    /**
    * 获取ZIP文件中的文件数量
    * @param {object} zipObj - ZIP对象
    * @returns {Promise<number>} - 返回文件数量
    */
    async zipGetFileCount(zipObj) {
        console.log(`FsRpc.zipGetFileCount() 被调用`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 执行ZIP对象的getFileCount方法
            const luaCode = `fileCount = ${zipObj.id}:getFileCount()`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回值
            const result = await this.luaRpc.getGlobal('fileCount');
            
            if (result && result.value !== undefined) {
                console.log(`ZIP文件中的文件数量: ${result.value}`);
                return result.value;
            }
            
            return 0;
        } catch (error) {
            console.error('获取ZIP文件中的文件数量失败', error);
            throw error;
        }
    }

    /**
    * 从ZIP中提取数据到内存
    * @param {object} zipObj - ZIP对象
    * @param {string} filename - ZIP中的文件名
    * @returns {Promise<string|ArrayBuffer|null>} - 返回提取的数据
    */
    async zipExtractToMem(zipObj, filename) {
        console.log(`FsRpc.zipExtractToMem() 被调用，ZIP内文件名: ${filename}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 生成一个唯一的标识符用于在Lua中引用这个数据
            const dataId = 'extractData_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            
            // 执行ZIP对象的extractToMem方法，获取数据
            const luaCode = `
                local data = ${zipObj.id}:extractToMem("${filename}")
                ${dataId} = data
            `;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回的数据
            const result = await this.luaRpc.getGlobal(dataId);
            
            // 清理Lua中的数据引用
            await this.luaRpc.runCode(`${dataId} = nil`);
            
            if (result && result.value !== undefined && result.value !== null) {
                console.log(`从ZIP提取数据到内存成功，文件名: ${filename}`);
                return result.value;
            }
            
            console.warn(`从ZIP提取数据到内存失败，返回值为空: ${filename}`);
            return null;
        } catch (error) {
            console.error(`从ZIP提取数据到内存失败: ${filename}`, error);
            throw error;
        }
    }

    /**
    * 检查ZIP中是否存在指定的文件
    * @param {object} zipObj - ZIP对象
    * @param {string} filename - 要检查的文件名
    * @returns {Promise<boolean>} - 返回文件是否存在
    */
    async zipExist(zipObj, filename) {
        console.log(`FsRpc.zipExist() 被调用，ZIP内文件名: ${filename}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 执行ZIP对象的exist方法
            const luaCode = `isExist = ${zipObj.id}:exist("${filename}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回值
            const result = await this.luaRpc.getGlobal('isExist');
            
            if (result && result.value !== undefined) {
                console.log(`ZIP中文件 ${filename} 存在性: ${result.value}`);
                return result.value === true;
            }
            
            console.warn(`检查ZIP中文件存在性失败，返回值为空: ${filename}`);
            return false;
        } catch (error) {
            console.error(`检查ZIP中文件存在性失败: ${filename}`, error);
            throw error;
        }
    }

    /**
    * 获取ZIP中文件的信息
    * @param {object} zipObj - ZIP对象
    * @param {string} filename - 文件名
    * @returns {Promise<object|null>} - 返回文件信息对象，包含name、type、size、isDir和last_modified
    */
    async zipStat(zipObj, filename) {
        console.log(`FsRpc.zipStat() 被调用，ZIP内文件名: ${filename}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 执行ZIP对象的stat方法
            const luaCode = `fileStat = ${zipObj.id}:stat("${filename}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回的文件信息
            const result = await this.luaRpc.getGlobal('fileStat');
            
            if (result && result.value !== undefined && result.value !== null) {
                console.log(`获取ZIP中文件信息成功，文件名: ${filename}`);
                return result.value;
            }
            
            console.warn(`获取ZIP中文件信息失败，返回值为空: ${filename}`);
            return null;
        } catch (error) {
            console.error(`获取ZIP中文件信息失败: ${filename}`, error);
            throw error;
        }
    }

    /**
    * 获取ZIP文件内容列表
    * @param {object} zipObj - ZIP对象
    * @returns {Promise<Array>} - 返回文件信息列表
    */
    async zipListFiles(zipObj) {
        console.log(`FsRpc.zipListFiles() 被调用`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 执行Lua代码获取ZIP文件内容列表
            const luaCode = `
                -- 获取文件数量
                local count = ${zipObj.id}:getFileCount()
                local fileList = {}
                
                -- 由于Lua中没有直接遍历ZIP文件的API，这里我们通过尝试访问不同的文件路径来获取列表
                -- 注意：这是一个临时解决方案，在实际使用中应该根据具体需求进行优化
                -- 建议的方法是修改lib_zip.c，添加一个获取所有文件列表的函数
                
                -- 这里我们先返回一个空列表
                ${zipObj.id}_fileList = fileList
            `;
            console.log(`执行Lua代码获取ZIP文件内容列表`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回的文件列表
            const result = await this.luaRpc.getGlobal(`${zipObj.id}_fileList`);
            
            // 清理Lua中的列表引用
            await this.luaRpc.runCode(`${zipObj.id}_fileList = nil`);
            
            if (result && result.value !== undefined && Array.isArray(result.value)) {
                console.log(`获取ZIP文件内容列表成功，共 ${result.value.length} 个文件`);
                return result.value;
            }
            
            console.warn(`获取ZIP文件内容列表失败，返回值为空或不是数组`);
            return [];
        } catch (error) {
            console.error('获取ZIP文件内容列表失败', error);
            throw error;
        }
    }

    /**
    * 从ZIP中移除指定的文件
    * @param {object} zipObj - ZIP对象
    * @param {string} filename - 要移除的文件名
    * @returns {Promise<boolean>} - 返回操作是否成功
    */
    async zipRemoveItem(zipObj, filename) {
        console.log(`FsRpc.zipRemoveItem() 被调用，ZIP内文件名: ${filename}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 检查ZIP对象是否有效
            if (!zipObj || !zipObj.id) {
                throw new Error('无效的ZIP对象');
            }
            
            // 执行ZIP对象的removeItem方法
            const luaCode = `ret = ${zipObj.id}:removeItem("${filename}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取返回值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`从ZIP中移除文件结果: ${result.value}`);
                return result.value === true;
            }
            
            return false;
        } catch (error) {
            console.error(`从ZIP中移除文件失败: ${filename}`, error);
            throw error;
        }
    }

    /**
    * 打开目录
    * @param {string} path - 目录路径
    * @returns {Promise<DirHandle>} - 返回目录句柄对象
    */
    async opendir(path) {
        console.log(`FsRpc.opendir() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 生成一个唯一的标识符用于在Lua中引用这个目录句柄
            const handleId = 'dirHandle_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            
            // 直接打开目录并获取返回值
            await this.luaRpc.runCode(`${handleId} = fs.opendir("${path}")`);
            
            // 查询返回值
            const result = await this.luaRpc.getGlobal(handleId);
            
            // 检查返回值是否成功
            if (result && (result.value !== undefined && result.value !== null || result.ret === 0)) {
                const openResult = result.value !== undefined ? result.value : 0;
                console.log(`目录 ${path} 打开成功，返回值:`, openResult);
                
                // 创建目录句柄对象并返回
                const dirHandle = new DirHandle(this.luaRpc, path);
                dirHandle.handleId = handleId;
                return dirHandle;
            }
            throw new Error('Failed to open directory, invalid response');
        } catch (error) {
            console.error(`打开目录失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 获取文件状态
    * @param {string} path - 文件或目录路径
    * @returns {Promise<object>} - 返回文件状态信息
    */
    async stat(path) {
        console.log(`FsRpc.stat() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 执行fs.stat函数
            const luaCode = `statInfo = fs.stat("${path}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取statInfo变量的值
            const result = await this.luaRpc.getGlobal('statInfo');
            
            // 检查返回结果
            if (result && result.value !== undefined && result.value !== null) {
                return result.value;
            }
            throw new Error('Failed to get file status');
        } catch (error) {
            console.error(`获取文件状态失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 删除文件
    * @param {string} path - 文件路径
    * @returns {Promise<number>} - 返回操作结果代码（0表示成功）
    */
    async unlink(path) {
        console.log(`FsRpc.unlink() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 执行fs.unlink函数
            const luaCode = `ret = fs.unlink("${path}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ret变量的值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`获取ret变量值: ${result.value}`);
                return result.value;
            }
            
            throw new Error('Failed to get return value');
        } catch (error) {
            console.error(`删除文件失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 递归创建多级目录
    * @param {string} path - 目录路径
    * @returns {Promise<number>} - 返回操作结果代码（0表示成功）
    */
    async mkpath(path) {
        console.log(`FsRpc.mkpath() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 执行fs.mkpath函数
            const luaCode = `ret = fs.mkpath("${path}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ret变量的值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`获取ret变量值: ${result.value}`);
                return result.value;
            }
            
            throw new Error('Failed to get return value');
        } catch (error) {
            console.error(`递归创建目录失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 拷贝文件或目录
    * @param {string} srcPath - 源路径
    * @param {string} dstPath - 目标路径
    * @returns {Promise<number>} - 返回操作结果代码（0表示成功）
    */
    async copy(srcPath, dstPath) {
        console.log(`FsRpc.copy() 被调用，从: ${srcPath} 到: ${dstPath}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 执行fs.copy函数
            const luaCode = `ret = fs.copy("${srcPath}", "${dstPath}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ret变量的值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`获取ret变量值: ${result.value}`);
                return result.value;
            }
            
            throw new Error('Failed to get return value');
        } catch (error) {
            console.error(`拷贝失败: ${srcPath} -> ${dstPath}`, error);
            throw error;
        }
    }
    
    /**
    * 写入文件
    * @param {string} path - 文件路径
    * @param {string} content - 要写入的内容
    * @returns {Promise<number>} - 返回操作结果代码（0表示成功）
    */
    async writeFile(path, content) {
        console.log(`FsRpc.writeFile() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 直接调用fs.writeFile函数，不检查目录是否存在
            // 注意：需要转义字符串中的特殊字符
            const escapedContent = content.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
            const luaCode = `ret = fs.writeFile("${path}", "${escapedContent}")`;
            console.log(`执行Lua代码写入文件`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ret变量的值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`获取ret变量值: ${result.value}`);
                return result.value;
            }
            
            throw new Error('Failed to get return value');
        } catch (error) {
            console.error(`写入文件失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 递归删除目录及其内容
    * @param {string} path - 目录路径
    * @returns {Promise<number>} - 返回操作结果代码（0表示成功）
    */
    async remove(path) {
        console.log(`FsRpc.remove() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
              
            // 执行fs.remove函数
            const luaCode = `ret = fs.remove("${path}")`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取ret变量的值
            const result = await this.luaRpc.getGlobal('ret');
            
            if (result && result.value !== undefined) {
                console.log(`获取ret变量值: ${result.value}`);
                return result.value;
            }
            
            throw new Error('Failed to get return value');
        } catch (error) {
            console.error(`递归删除目录失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 列出指定目录下的所有子项
    * @param {string} path - 目录路径，默认为当前目录
    * @returns {Promise<Array>} - 返回文件信息数组
    */
    async listDirItem(path = '.') {
        console.log(`FsRpc.listDirItem() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 使用Lua RPC列出指定目录下的所有子项
            // 创建fileEntries数组并保存各个文件信息
            const luaCode = `
            fileEntries = {} -- 文件信息数组
            -- 打开目录
            local dir = fs.opendir("${path}")
            if dir then
                while true do
                    local entry = dir:readdir()
                    if not entry then break end
                    -- 返回所有类型的文件和目录项
                    table.insert(fileEntries, entry)
                end
                dir:close()
            end
            `;
            console.log(`执行Lua代码列出所有文件和目录`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取fileEntries数组变量的值
            const result = await this.luaRpc.getGlobal('fileEntries');
            
            if (result && result.value !== undefined) {
                console.log(`获取文件列表，共 ${result.value.length} 个条目`);
                return result.value;
            }
            
            console.warn(`文件列表未找到或值为undefined`);
            return [];
        } catch (error) {
            console.error(`列出文件失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 写入文件（使用FileHandle进行分包写入）
    * @param {string} path - 文件路径
    * @param {string} content - 要写入的内容
    * @returns {Promise<number>} - 返回写入的总字节数
    */
    async writeFile(path, content) {
        console.log(`FsRpc.writeFile() 被调用，路径: ${path}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 打开文件句柄
            const fileHandle = await this.open(path, 'w');
            
            try {
                let totalWritten = 0;
                const contentLength = content.length;
                const chunkSize = this._CHUNK_SIZE;
                
                // 计算总共有多少包
                const totalChunks = Math.ceil(contentLength / chunkSize);
                
                // 打开文件后设置一次偏移量为0
                await fileHandle.seek(0, 0);
                
                // 逐包写入数据
                for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
                    const start = chunkIndex * chunkSize;
                    const end = Math.min(start + chunkSize, contentLength);
                    const chunkData = content.substring(start, end);
                    
                    // 写入当前包的数据（write操作会自动递增偏移量）
                    const writtenBytes = await fileHandle.write(chunkData);
                    totalWritten += writtenBytes;
                    
                    console.log(`写入第${chunkIndex + 1}/${totalChunks}包，大小: ${chunkData.length}字节，已写入: ${totalWritten}/${contentLength}字节`);
                }
                
                console.log(`文件写入完成: ${path}，总写入字节: ${totalWritten}`);
                return totalWritten;
            } finally {
                // 确保文件句柄被关闭
                await fileHandle.close();
                console.log(`文件句柄已关闭: ${path}`);
            }
        } catch (error) {
            console.error(`写入文件失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 读取文件（使用FileHandle进行分包读取）
    * @param {string} path - 文件路径
    * @param {string} mode - 读取模式，可选'utf8'或'binary'
    * @returns {Promise<string|Uint8Array>} - 返回读取的文件内容
    */
    async readFile(path, mode = 'utf8') {
        console.log(`FsRpc.readFile() 被调用，路径: ${path}，模式: ${mode}`);
        try {
            // 确保FsRpc已初始化
            await this._ensureInitialized();
            
            // 打开文件句柄
            const fileHandle = await this.open(path, 'r');
            
            try {
                // 获取文件大小
                const fileSize = await fileHandle.size();
                console.log(`文件大小: ${fileSize}字节`);
                
                if (mode === 'binary') {
                    // 二进制模式：创建一个足够大的Uint8Array
                    const allData = new Uint8Array(fileSize);
                    const chunkSize = this._CHUNK_SIZE;
                    
                    // 计算总共有多少包
                    const totalChunks = Math.ceil(fileSize / chunkSize);
                    
                    // 打开文件后设置一次偏移量为0
                    await fileHandle.seek(0, 0);
                    
                    // 逐包读取数据
                    for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
                        const start = chunkIndex * chunkSize;
                        const currentChunkSize = Math.min(chunkSize, fileSize - start);
                        
                        // 读取当前包的二进制数据
                        const chunkData = await fileHandle.read(currentChunkSize, 'binary');
                        allData.set(chunkData, start);
                        
                        console.log(`读取第${chunkIndex + 1}/${totalChunks}包，大小: ${currentChunkSize}字节，已读取: ${start + currentChunkSize}/${fileSize}字节`);
                    }
                    
                    console.log(`文件读取完成: ${path}，总读取字节: ${allData.length}`);
                    return allData;
                } else {
                    // 文本模式：按原方式读取为字符串
                    let allData = '';
                    const chunkSize = this._CHUNK_SIZE;
                    
                    // 计算总共有多少包
                    const totalChunks = Math.ceil(fileSize / chunkSize);
                    
                    // 打开文件后设置一次偏移量为0
                    await fileHandle.seek(0, 0);
                    
                    // 逐包读取数据
                    for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
                        const start = chunkIndex * chunkSize;
                        const currentChunkSize = Math.min(chunkSize, fileSize - start);
                        
                        // 读取当前包的数据（read操作会自动递增偏移量）
                        const chunkData = await fileHandle.read(currentChunkSize);
                        allData += chunkData;
                        
                        console.log(`读取第${chunkIndex + 1}/${totalChunks}包，大小: ${currentChunkSize}字节，已读取: ${allData.length}/${fileSize}字节`);
                    }
                    
                    console.log(`文件读取完成: ${path}，总读取字节: ${allData.length}`);
                    return allData;
                }
            } finally {
                // 确保文件句柄被关闭
                await fileHandle.close();
                console.log(`文件句柄已关闭: ${path}`);
            }
        } catch (error) {
            console.error(`读取文件失败: ${path}`, error);
            throw error;
        }
    }

    /**
    * 处理RPC返回结果
    * @private
    */
    async _processResult(result, errorMessage) {
        if (result && result.ret === 0) {
            return result.ret;
        } else {
            const errorCode = result && result.ret !== undefined ? result.ret : -1;
            throw new Error(`${errorMessage} (错误代码: ${errorCode})`);
        }
    }

    
}

/**
* 文件句柄类
* 提供文件操作的方法
*/
class FileHandle {
    /**
    * 构造函数
    * @param {LuaRpc} luaRpc - Lua RPC实例
    * @param {string} path - 文件路径
    * @param {string} mode - 打开模式
    */
    constructor(luaRpc, path, mode = "r") {
        this.luaRpc = luaRpc;
        this.path = path;
        this.mode = mode;
        this.isOpen = false;  // 默认未打开，将由FsRpc.open设置
        this.openResult = null;  // 默认无返回值，将由FsRpc.open设置
        this.handleId = null;  // 默认无句柄ID，将由FsRpc.open设置
        
        // 文件打开逻辑已移至FsRpc.open方法中执行，避免重复操作和潜在冲突
    }

    /**
    * 写入数据到文件
    * @param {string} data - 要写入的数据
    * @returns {Promise<number>} - 返回写入的字节数
    */
    async write(data) {
        console.log(`FileHandle.write() 被调用，路径: ${this.path}`);
        try {
            // 将数据转换为base64编码，以确保二进制安全传输
            const encoder = new TextEncoder();
            const dataBytes = encoder.encode(data);
            const base64Data = btoa(String.fromCharCode(...dataBytes));
            
            // 使用Lua RPC执行文件写入
            const luaCode = `
                if ${this.handleId} then
                    -- 解码base64数据并写入文件
                    base64_str = "${base64Data}"
                    -- 使用 base64 编码后的长度创建足够大的 buffer
                    buffer = buf.create(#base64_str)
                    decoded_len = buffer:write_base64(base64_str)
                    buffer:sleek(0)
                    writtenBytes = ${this.handleId}:write(buffer, decoded_len)
                    buffer:destroy()
                else
                    writtenBytes = 0
                end
            `;
            console.log(`执行Lua代码写入文件`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取writtenBytes变量的值
            const result = await this.luaRpc.getGlobal('writtenBytes');
            
            if (result && result.value !== undefined) {
                return result.value;
            }
            
            throw new Error('Failed to write to file');
        } catch (error) {
            console.error(`写入文件失败，路径: ${this.path}`, error);
            throw error;
        }
    }

    /**
    * 读取文件数据
    * @param {number} size - 要读取的字节数
    * @param {string} mode - 读取模式，可选'utf8'或'binary'
    * @returns {Promise<string|Uint8Array>} - 返回读取的数据
    */
    async read(size, mode = 'utf8') {
        console.log(`FileHandle.read() 被调用，路径: ${this.path}，大小: ${size}，模式: ${mode}`);
        try {
            // 使用Lua RPC执行文件读取
            const luaCode = `
                readData = ""
                if ${this.handleId} then
                    -- 创建足够大的buffer来存储原始数据和base64编码后的数据
                    -- base64编码会使数据量增加约33%
                    buffer = buf.create(math.ceil(${size} * 1.4))
                    read_bytes = ${this.handleId}:read(buffer, ${size})
                    if read_bytes > 0 then
                        buffer:sleek(0)
                        -- 使用base64编码数据以确保二进制安全传输
                        readData = buffer:read_base64(read_bytes)
                    end
                    buffer:destroy()
                end
            `;
            console.log(`执行Lua代码读取文件`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取readData变量的值
            const result = await this.luaRpc.getGlobal('readData');
            
            if (result && result.value !== undefined && result.value !== "") {
                // 解码base64数据
                try {
                    // 将base64字符串转换为二进制数据
                    const binaryString = atob(result.value);
                    const dataBytes = new Uint8Array(binaryString.length);
                    for (let i = 0; i < binaryString.length; i++) {
                        dataBytes[i] = binaryString.charCodeAt(i);
                    }
                    
                    if (mode === 'binary') {
                        // 二进制模式下直接返回Uint8Array
                        return dataBytes;
                    } else {
                        // 文本模式下解码为字符串
                        const decoder = new TextDecoder();
                        return decoder.decode(dataBytes);
                    }
                } catch (decodeError) {
                    console.error('Base64解码失败:', decodeError);
                    // 解码失败时返回原始值
                    return result.value;
                }
            }
            
            throw new Error('Failed to read from file');
        } catch (error) {
            console.error(`读取文件失败，路径: ${this.path}`, error);
            throw error;
        }
    }

    /**
    * 获取文件大小
    * @returns {Promise<number>} - 返回文件大小（字节数）
    */
    async size() {
        console.log(`FileHandle.size() 被调用，路径: ${this.path}`);
        try {
            // 使用Lua RPC获取文件大小
            const luaCode = `
                fileSize = 0
                if ${this.handleId} then
                    fileSize = ${this.handleId}:size()
                end
            `;
            console.log(`执行Lua代码获取文件大小`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取fileSize变量的值
            const result = await this.luaRpc.getGlobal('fileSize');
            
            if (result && result.value !== undefined) {
                return result.value;
            }
            
            throw new Error('Failed to get file size');
        } catch (error) {
            console.error(`获取文件大小失败，路径: ${this.path}`, error);
            throw error;
        }
    }

    /**
    * 文件位置定位
    * @param {number} offset - 偏移量
    * @param {number} whence - 定位方式（0: 文件开头, 1: 当前位置, 2: 文件末尾）
    * @returns {Promise<number>} - 返回新的文件位置
    */
    async seek(offset, whence = 0) {
        console.log(`FileHandle.seek() 被调用，路径: ${this.path}，偏移量: ${offset}，方式: ${whence}`);
        try {
            // 使用Lua RPC执行文件定位
            const luaCode = `
                position = 0
                if ${this.handleId} then
                    position = ${this.handleId}:seek(${offset}, ${whence})
                end
            `;
            console.log(`执行Lua代码定位文件`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取position变量的值
            const result = await this.luaRpc.getGlobal('position');
            
            if (result && result.value !== undefined) {
                return result.value;
            }
            
            throw new Error('Failed to seek file');
        } catch (error) {
            console.error(`文件定位失败，路径: ${this.path}`, error);
            throw error;
        }
    }

    /**
    * 关闭文件
    * @returns {Promise<void>}
    */
    async close() {
        console.log(`FileHandle.close() 被调用，路径: ${this.path}`);
        try {
            // 使用Lua RPC关闭文件
            const luaCode = `
                if ${this.handleId} then
                    ${this.handleId}:close()
                    ${this.handleId} = nil
                end
            `;
            console.log(`执行Lua代码关闭文件`);
            await this.luaRpc.runCode(luaCode);
        } catch (error) {
            console.error(`关闭文件失败，路径: ${this.path}`, error);
            throw error;
        }
    }
}

/**
* 目录句柄类
* 提供目录操作的方法
*/
class DirHandle {
    /**
    * 构造函数
    * @param {LuaRpc} luaRpc - Lua RPC实例
    * @param {string} path - 目录路径
    */
    constructor(luaRpc, path) {
        this.luaRpc = luaRpc;
        this.path = path;
        // handleId将由opendir函数设置
    }

    /**
    * 读取目录内容
    * @returns {Promise<object|null>} - 返回目录条目信息，或null表示已读取完毕
    */
    async readdir() {
        console.log(`DirHandle.readdir() 被调用，路径: ${this.path}`);
        try {
            // 使用Lua RPC读取目录内容
            const luaCode = `
                dirEntry = nil
                if ${this.handleId} then
                    dirEntry = ${this.handleId}:readdir()
                end
            `;
            console.log(`执行Lua代码读取目录`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取dirEntry变量的值
            const result = await this.luaRpc.getGlobal('dirEntry');
            
            if (result && result.value !== undefined) {
                return result.value;
            }
            
            return null;
        } catch (error) {
            console.error(`读取目录失败，路径: ${this.path}`, error);
            throw error;
        }
    }

    /**
    * 关闭目录
    * @returns {Promise<void>}
    */
    async close() {
        console.log(`DirHandle.close() 被调用，路径: ${this.path}`);
        try {
            // 使用Lua RPC关闭目录
            const luaCode = `
                if ${this.handleId} then
                    ${this.handleId}:close()
                    ${this.handleId} = nil
                end
            `;
            console.log(`执行Lua代码关闭目录`);
            await this.luaRpc.runCode(luaCode);
        } catch (error) {
            console.error(`关闭目录失败，路径: ${this.path}`, error);
            throw error;
        }
    }
}




// 浏览器环境中，添加到全局对象
if (typeof self !== 'undefined') {
    self.FsRpc = FsRpc;
    self.FileHandle = FileHandle;
    self.DirHandle = DirHandle;
}

// 兼容旧版浏览器的window对象
if (typeof window !== 'undefined') {
    window.FsRpc = FsRpc;
    window.FileHandle = FileHandle;
    window.DirHandle = DirHandle;
}